package com.pangu.service;

import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.pangu.AMApplication;
import com.pangu.bean.ContextConfig;
import com.pangu.bean.DeviceConfig;
import com.pangu.service.impl.ProtocolWrap;
import com.pangu.util.HttpUtils;
import com.pangu.util.MConstants;
import com.pangu.util.PersistentCookieStore;
import com.pangu.util.network.NetworkInfoParser;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

/**
 * 完成一些公共的网络请求
 * <p/>
 * Created by cuijianhui_91
 */

public abstract class AHttpRequestService {

	// 最小post 数据是启动压缩
	private static final int COMPRESSION_MIN_SIZE = 2048;
	protected final String TAG;
	// 基础环境
	protected AMApplication imContext;

	public AHttpRequestService(AMApplication imContext, String tag) {
		this.imContext = imContext;
		this.TAG = tag;
	}

	/**
	 * 获取HTTP通用头部
	 * 
	 * @param imContext
	 * @param protocolWrap
	 * @return
	 */
	public static Map<String, String> getHttpRequestHeaders(AMApplication imContext, ProtocolWrap protocolWrap) {
		Map<String, String> headers = new HashMap<String, String>();
		// 明确指定连接完成后断开
		headers.put("Connection", "close");

		DeviceConfig deviceConfig = imContext.getDeviceConfig();
		ContextConfig mobConfig = imContext.getContextConfig();
		// // 加密的数据
		// StringBuffer encodedSb = new StringBuffer();
		// // 数值为null上传""保证空判断正确，其中session从sharedpref中取值，只取一次
		// String sessionId = imContext.getSessionId();
		// encodedSb.append(MConstants.H_SESSION_ID + "=" + (sessionId == null ?
		// "" : sessionId));
		// encodedSb.append("&");
		// encodedSb.append(MConstants.H_SER_TS + "=" + (imContext.getTs() ==
		// null ? "" : imContext.getTs()));
		// encodedSb.append("&");
		// encodedSb.append(MConstants.H_CHANNEL + "=" + (mobConfig.getCid() ==
		// null ? "" : mobConfig.getCid()));
		// encodedSb.append("&");
		// encodedSb.append(MConstants.H_MAC + "=" + (deviceConfig.getMac() ==
		// null ? "" : deviceConfig.getMac()));
		// encodedSb.append("&");
		// encodedSb.append(MConstants.H_DEVICE + "=" + (deviceConfig.getImei()
		// == null ? "" : deviceConfig.getImei()));
		// encodedSb.append("&");
		// encodedSb.append(MConstants.H_IMSI + "=" + (deviceConfig.getSimId()
		// == null ? "" : deviceConfig.getSimId()));
		// encodedSb.append("&");
		// encodedSb.append(MConstants.H_USER_UUID + "=" +
		// (deviceConfig.getUserUuid() == null ? "" : deviceConfig
		// .getUserUuid()));
		// encodedSb.append(MConstants.H_USER_ID + "=" + (mobConfig.getUserid()
		// == null ? "" : mobConfig.getUserid()));
		// String encodedStr = "";
		// try {
		// encodedStr =
		// StringUtil.encodeContentForUrl(EncDec.encrypt(imContext.getDeviceConfig().getDesKey(),
		// encodedSb.toString()));
		//
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		// headers.put(MConstants.H_ENCODED_CLIENT_PARAMS, encodedStr);
		//
		// // 基本配置和环境参数
		// headers.put(MConstants.H_CLIENT_MARK,
		// String.valueOf(imContext.getClientMark()));
		// headers.put(MConstants.H_MODEL, deviceConfig.getModel());
		// headers.put(MConstants.H_NET_TYPE,
		// NetworkInfoParser.getRawNetExtraType(imContext));
		// headers.put(MConstants.H_NET_CODE,
		// String.valueOf(NetworkInfoParser.getRawNetType(imContext)));
		// headers.put(MConstants.H_CLIENT_VERSION, deviceConfig.getVersion());
		// headers.put(MConstants.H_CLIENT_VERSIONCODE,
		// String.valueOf(deviceConfig.getVersionCode()));
		//
		// // 机型最优过滤参数
		// headers.put(MConstants.H_RESOLUTION, deviceConfig.getResolution());
		// headers.put(MConstants.H_DENSITY, deviceConfig.getDensity());
		// headers.put(MConstants.H_SDK_VERSION,
		// String.valueOf(deviceConfig.getSdkVersion()));
		// headers.put(MConstants.H_VENDER, mobConfig.getVid());
		// headers.put(MConstants.H_ABI, deviceConfig.getAbi());

		headers.put(MConstants.H_API_KEY, mobConfig.getApikey());
		// 业务附带的头部信息，注意这里将覆盖原来存在的header值
		if (protocolWrap != null && protocolWrap.getHeaderValues() != null && protocolWrap.getHeaderValues().size() > 0) {
			headers.putAll(protocolWrap.getHeaderValues());
		}

		return headers;
	}

	/**
	 * 执行请求,只有返回HTTP_OK才有结果，其他抛出ServiceException
	 * 
	 * @param protocol
	 * @return
	 * @throws ActionException
	 */
	protected final byte[] requestServiceResource(ProtocolWrap protocol) throws ActionException {
		try {
			// 连接状态,检查尝试选择适合的连接信息
			String urlStr;
			if (protocol.getHost() == null) {
				urlStr = getDefaultHostUrl();
				urlStr = checkUrlProtocol(protocol, urlStr);
				protocol.setHost(urlStr); // 设置host
			}

			// 执行数据请求
			return doRequestServiceResource(protocol);

		} catch (Exception ex) {
			ex.printStackTrace();
			if (ex instanceof ActionException) {
				throw (ActionException) ex;

			} else if (ex.getCause() instanceof ActionException) {
				throw (ActionException) ex.getCause();

			} else if (ex instanceof SocketException) {
				throw new ActionException(ActionException.NETWORK_ERROR, "network error, please check network:"
						+ ex.toString(), ex);

			} else {
				throw new ActionException(ActionException.OPERATE_ERROR, "operate error:" + ex.toString(), ex);
			}
		}
	}

	/**
	 * 检查请求协议
	 * 
	 * @param protocol
	 * @param urlStr
	 * @return
	 */
	private String checkUrlProtocol(ProtocolWrap protocol, String urlStr) {
		if (protocol.isHttps()) {
			urlStr = "https://" + urlStr;

		} else {
			urlStr = "http://" + urlStr;
		}

		return urlStr;
	}

	/**
	 * 执行请求,只有返回HTTP_OK才有结果，其他抛出ServiceException 注意：业务层禁止直接调用次方法
	 * 
	 * @param protocol
	 * @return
	 * @throws Exception
	 */
	final byte[] doRequestServiceResource(ProtocolWrap protocol) throws Exception {
		Response response = null;
		byte[] result = null;
		try {
			// 发送请求
			OkHttpClient client = NetworkInfoParser.getHttpConnector(imContext);
			client.setCookieHandler(new CookieManager(new PersistentCookieStore(imContext), CookiePolicy.ACCEPT_ALL));
			if (protocol.isHttps()) {
				KeyStore keyStore;
				// 如果是自己的链接，则使用默认证书
				if (protocol.getHost().indexOf(getDefaultHostUrl()) >= 0) {
					keyStore = imContext.getContextConfig().getHttpsCertificate();

				} else {
					// 如果是外部链接，则使用单独的证书
					keyStore = protocol.getHttpsKeyStore();
				}

				client.setSslSocketFactory(HttpUtils.createTrustedSslSocketFactory(keyStore));
				client.setHostnameVerifier(HttpUtils.createTrustAllHostNameVerifier());
			}

			// 超时设置
			// 连接超时
			client.setConnectTimeout(protocol.getConnectTimeout() > 0 ? protocol.getConnectTimeout()
					: MConstants.DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
			// 读取超时
			client.setReadTimeout(
					protocol.getSoTimeout() > 0 ? protocol.getSoTimeout() : MConstants.DEFAULT_SO_TIMEOUT,
					TimeUnit.MILLISECONDS);

			// 非调试状态下，尝试把域名部分替换成ip，也有可能还是替换成原域名，主要看哪个是最优地址
			// 如果调试地址绑定的开关打开，则不进行地址绑定
			String urlStr = protocol.getHost();
			// url参数部分，自动补充tt时间戳避免被缓存
			if (protocol.getGetData() != null) {
				urlStr = urlStr + "?" + protocol.getGetData() + "&tt=" + System.currentTimeMillis();
			}

			Request.Builder requestBuilder = new Request.Builder().url(urlStr);

			// post数据部分
			if (protocol.getPostBody() != null) {
				RequestBody body = protocol.getPostBody();

				requestBuilder.post(body);
			}

			// 头部部分
			initRequestHeaders(requestBuilder, protocol);

			Request request = requestBuilder.build();

			// 执行
			response = client.newCall(request).execute();
			int httpCode = response.code();

			if (httpCode == HttpURLConnection.HTTP_OK) {
				result = response.body().bytes();

			} else {
				throw new ActionException(ActionException.OPERATE_ERROR, httpCode, "operate httpcode error:" + httpCode);
			}

		} finally {
			if (response != null) {
				try {
					response.body().close();

				} catch (Exception e) {
				}
			}
		}

		return result;
	}

	/**
	 * 初始化请求的头部信息
	 * 
	 * @param requestBuilder
	 * @param protocol
	 */
	protected void initRequestHeaders(Request.Builder requestBuilder, ProtocolWrap protocol) {
		// 获取统一http header参数
		Map<String, String> headersMap = getHttpRequestHeaders(imContext, protocol);
		for (String key : headersMap.keySet()) {
			requestBuilder.addHeader(key, headersMap.get(key) == null ? "" : headersMap.get(key));
		}
	}

	/**
	 * 获得默认的主机域名
	 * 
	 * @return
	 */
	protected abstract String getDefaultHostUrl();

}
